﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Threading;

namespace BusinessLayer
{
    public class ChartBusiness
    {
        private const string Red = "#FF0000";
        private DateTime fromDateTime;
        private DateTime toDateTime;
        private FunctionTestItem functionalTestItem = new FunctionTestItem();

        private InputData inputData;
        public ChartBusiness(InputData data)
        {
            inputData = data;
            PrepareDate();
            PrepareFunctionalTestID();
        }

        public ChartData GetChartData()
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("zh-CN"); //fran

            ChartData chartData = new ChartData();
            
            OutputData outputdata = new OutputData();

            outputdata.FunctionalTestID = functionalTestItem.FunctionalTestID;
            outputdata.FunctionalTestDes = functionalTestItem.FunctionalTestDes;
            outputdata.TestPlanID = functionalTestItem.TestPlanID;
            outputdata.PartNoID = functionalTestItem.PartNoID;
            outputdata.TestPlanDes = functionalTestItem.TestPlanDes;
            outputdata.IsRemark = MetrixDataBusiness.IsRemark(functionalTestItem.TestPlanID, functionalTestItem.FunctionalTestID);
            chartData.OutputData = outputdata;

            List<TestResultData> testResultDataList = ChartDataAccess.GetChartBusiness(fromDateTime, toDateTime, functionalTestItem.TestPlanID, functionalTestItem.FunctionalTestID);
            List<TestResultData> removeDuplicateList = (from t in testResultDataList
                                                        group t by new { t.Year, t.Month, t.Day, t.Hour } into g
                                                        select g.First()).OrderBy(p => p.Year).ThenBy(p => p.Month).ThenBy(p => p.Day).ThenBy(p => p.Hour).ToList();

            if (removeDuplicateList.Count <= 1)
            {
                chartData.HasChart = false;
                return chartData;
            }
            chartData.HasChart = true;

            //average;
            decimal individualAverage = Math.Round(removeDuplicateList.Average(p => p.ResultValue), 2);

            individualAverage = GetStrbar(individualAverage, inputData.XBar);

            TestResultData previousData = removeDuplicateList[0];
            //categories
            List<string> categories = new List<string>();
            categories.Add(new DateTime(previousData.Year, previousData.Month, previousData.Day, previousData.Hour, 0, 0).ToString("MM/dd HH:mm"));

            List<decimal> individualList = new List<decimal>();
            individualList.Add(previousData.ResultValue);

            List<decimal> movingList = new List<decimal>();
            //lineData
            List<Point> individualPointList = new List<Point>();
            individualPointList.Add(new Point() { y = previousData.ResultValue });
            List<Point> movingPointList = new List<Point>();

            for (int i = 1; i < removeDuplicateList.Count; i++)
            {
                TestResultData data = removeDuplicateList[i];
                categories.Add(ConvertDateString(previousData, data));
                individualList.Add(data.ResultValue);
                Point iPoint = new Point() { y = data.ResultValue };
                individualPointList.Add(iPoint);

                movingList.Add(data.ResultValue - previousData.ResultValue);
                movingPointList.Add(new Point() { y = Math.Abs(data.ResultValue - previousData.ResultValue) });
                previousData = data;
            }

            List<ChangeFlag> averageRedList = GetChangeFlagList(individualList, individualAverage, 7);
            List<ChangeFlag> movingRedList = GetChangeFlagList(movingList, 0, 5);

            foreach (ChangeFlag flag in averageRedList)
            {
                for (int i = flag.StartIndex; i <= flag.EndIndex; i++)
                {
                    individualPointList[i].color = Red;
                }
            }


            foreach (ChangeFlag flag in movingRedList)
            {
                for (int i = flag.StartIndex; i <= flag.EndIndex + 1; i++)
                {
                    individualPointList[i].color = Red;
                }
            }

            List<decimal> movingValueList = movingPointList.Select(p => p.y).ToList();
            List<decimal> movingMarginValueList = new List<decimal>();

            if (movingValueList.Count > 0)
            {
                for (int i = 1; i < movingValueList.Count; i++)
                {
                    movingMarginValueList.Add(movingValueList[i] - movingValueList[i - 1]);
                }
            }
            
            decimal movingAverage = Math.Round(movingPointList.Average(p => p.y), 2);
            movingAverage = GetStrbar(movingAverage, inputData.RBar);

            List<ChangeFlag> averageMovingRedList = GetChangeFlagList(movingValueList, movingAverage, 7);
            List<ChangeFlag> movingMarginReadList = GetChangeFlagList(movingMarginValueList, 0, 5);

            foreach (ChangeFlag flag in averageMovingRedList)
            {
                for (int i = flag.StartIndex; i <= flag.EndIndex; i++)
                {
                    movingPointList[i].color = Red;
                }
            }

            foreach (ChangeFlag flag in movingMarginReadList)
            {
                for (int i = flag.StartIndex; i <= flag.EndIndex + 1; i++)
                {
                    movingPointList[i].color = Red;
                }
            }

            UCLLCLBusiness uclLCLBusiness = new UCLLCLBusiness(individualAverage, movingAverage, inputData.IsUCLFixed, inputData.IsUCLRFixed, functionalTestItem.TestPlanID, functionalTestItem.FunctionalTestID);
            decimal ucl = uclLCLBusiness.UCL;
            decimal lcl = uclLCLBusiness.LCL;
            decimal uclr = uclLCLBusiness.UCLR;

            foreach (Point point in individualPointList)
            {
                if (point.y > ucl || point.y < lcl)
                {
                    point.color = Red;
                }
            }

            foreach (Point point in movingPointList)
            {
                if (point.y > uclr)
                {
                    point.color = Red;
                }
            }

            IndividualChart individualChart = new IndividualChart();
            individualChart.AverageValue = individualAverage;
            individualChart.Categories = categories;
            individualChart.LCLValue = lcl;
            individualChart.LineData = individualPointList;
            USLLSLBusiness uslLSLBusiness = new USLLSLBusiness(functionalTestItem.TestPlanID, functionalTestItem.FunctionalTestID);
            individualChart.LSLValue = uslLSLBusiness.LSL;
            individualChart.UCLValue = ucl;
            individualChart.USLValue = uslLSLBusiness.USL;

            MovingRangeChart movingRangeChart = new MovingRangeChart();
            movingRangeChart.AverageValue = movingAverage;
            movingRangeChart.Categories = categories;
            movingPointList.Insert(0, null);
            movingRangeChart.LineData = movingPointList;
            movingRangeChart.UCLValue = uclr;

            decimal cp = (individualChart.USLValue - individualChart.LSLValue) / (6 * (movingAverage / 1.128M));
            decimal cpu = (individualChart.USLValue - individualAverage) / (3 * (movingAverage / 1.128M));
            decimal cpl = (individualAverage - individualChart.LSLValue) / (3 * (movingAverage / 1.128M));
            chartData.OutputData.CP = Math.Round(cp, 2);
            chartData.OutputData.CPU = Math.Round(cpu, 2);
            chartData.OutputData.CPL = Math.Round(cpl, 2);
            chartData.OutputData.CPK = Math.Min(chartData.OutputData.CPL, chartData.OutputData.CPU);
            chartData.OutputData.ChartWidth = categories.Count * 23;

            chartData.IndividualChart = individualChart;
            chartData.MovingRangeChart = movingRangeChart;
            

            return chartData;

        }

        private decimal GetStrbar(decimal indivualAverage, string xBar)
        {
            if (string.IsNullOrEmpty(xBar))
            {
                return indivualAverage;
            }
            return Math.Round(Convert.ToDecimal(xBar), 2);
        }

        private int GetChangeIndex(int startIndex, bool isUp, List<decimal> list, decimal average)
        {
            if (isUp)
            {
                return list.FindIndex(startIndex, p => p < average);
            }
            else
            {
                return list.FindIndex(startIndex, p => p > average);
            }
        }

        private List<ChangeFlag> GetChangeFlagList(List<decimal> list, decimal average, int flagLenth)
        {
            List<ChangeFlag> changeFlagList = new List<ChangeFlag>();
            if (list.Count < flagLenth)
            {
                return changeFlagList;
            }

            int findIndex = 0;
            int startIndex = 0;
            bool isUp = list[0] > average ? true : false;
            while (findIndex > -1)
            {
                findIndex = GetChangeIndex(startIndex, isUp, list, average);
                if (findIndex > -1)
                {
                    if ((findIndex - startIndex) > flagLenth)
                    {
                        changeFlagList.Add(new ChangeFlag(){ StartIndex = startIndex, EndIndex = findIndex - 1});
                    }
                    startIndex = findIndex;
                    isUp = !isUp;
                }
              
            }
            if (list.Count - 1 - startIndex > flagLenth)
            {
                changeFlagList.Add(new ChangeFlag() { StartIndex = startIndex, EndIndex = list.Count - 1});
            }

            return changeFlagList;
           
 
        }

        private string ConvertDateString(TestResultData previousData, TestResultData currentData)
        {
            DateTime currentDateTime = new DateTime(currentData.Year, currentData.Month, currentData.Day, currentData.Hour, 0, 0);
            if (currentData.Day != previousData.Day)
            {
                return currentDateTime.ToString("MM/dd HH:mm");
            }

            return currentDateTime.ToString("HH:mm");
        }

        //private string ConvertDateTimeToString(int hour)

        private void PrepareDate()
        {
            fromDateTime = Convert.ToDateTime(string.Format("{0} {1}:00", inputData.FromDate, inputData.FromTime));
            if (inputData.IsFixed > 0)
            {
                toDateTime = Convert.ToDateTime(string.Format("{0} {1}:00", inputData.ToDate, inputData.ToTime));
            }
            else
            {
                toDateTime = Convert.ToDateTime(string.Format("{0} {1}:00", inputData.FromDate, inputData.ToTime));
            }
        }

        private void PrepareFunctionalTestID()
        {
            List<FunctionTestItem> functionalTestIDs = MetrixDataBusiness.GetFunctionalTestIDListByLine(inputData.LineID);
            int currentIndex = functionalTestIDs.FindIndex(p => p.PartNoID == inputData.PartNoID && p.TestPlanID == inputData.TestSeriesID && p.FunctionalTestID == inputData.FunctionalTestID);
            if (inputData.IsUseNextTestSeries > 0)
            {
                if (currentIndex < functionalTestIDs.Count - 1)
                {
                    functionalTestItem = functionalTestIDs[currentIndex + 1];
                }
                else
                {
                    functionalTestItem = functionalTestIDs[0];
                }

            }
            else if (inputData.IsFixed > 0)
            {
                functionalTestItem = functionalTestIDs[currentIndex];
            }
            else
            {
                functionalTestItem = functionalTestIDs[0];
            }
        }
    }
}
